﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using WorldBankBBS.Comms;
using WorldBankBBS.Data;
using WorldBankBBS.Handlers;
using WorldBankBBS.Input;
using WorldBankBBS.Pathing;
using WorldBankBBS.Resources;
using WorldBankBBS.Translators;
using Thread = System.Threading.Thread;

namespace WorldBankBBS.Logic
{
    public class BbsMain
    {
        private readonly ITranslator _translator = null;
        private readonly Session _session = null;

        public BbsMain(Session session)
        {
            _session = session;
            switch(session.Encoding)
            {
                case "ASCII": session["ScreenWidth"] = 40; break;
                case "PETSCII": session["ScreenWidth"] = 40; break;
                case "ANSI": session["ScreenWidth"] = 80; break;
            }
            _translator = session.Encoding.GetTranslator(session);
        }

        public void Start()
        {
            if (!((ITcpConnection)_session.Connection).TcpSocket.Connected) return;
            DisplayBanner();

            if (!_session.User.IsLoggedIn)
            {
                if (PreLogin != null) PreLogin(this, _session);

                if (Login != null)
                {
                    Login(this, _session);
                    if (!_session.LoginCompleted)
                    {
                        if (LoginFailed != null) LoginFailed(this, _session);
                        return;
                    }
                }
                else
                {
                    if (LoginFailed != null) LoginFailed(this, _session);
                }

                if (PostLogin != null) PostLogin(this, _session);

                MainMenu();

                Thread.Sleep(500);
            }
        }

        private List<Notification> _lastNotifiactions;
        private event TextInputHandler TextInput;
        private InputHandler _inputHandler = new InputHandler();

        private void MainMenu()
        {
            var translator = _session.Encoding.GetTranslator(_session);

            var router = new PathRouter(_session);

            while (true)
            {
                DisplayPrompt(translator);

                TextInput -= _inputHandler.OnTextInput;
                TextInput += _inputHandler.OnTextInput;

                var selection = TextInput(_session, translator, _session.Connection, 30, false);

                TextInput -= _inputHandler.OnTextInput;

                var number = -1;
                if (int.TryParse(selection, out number))
                {
                    if (number - 1 < _lastNotifiactions.Count)
                    {
                        using (var mh = new ModelHelper())
                        {
                            mh.BeginNewContext();
                            var uid = _lastNotifiactions[number - 1].NotificationUID;
                            var notification = mh.Context.Notifications.FirstOrDefault(
                                x => x.NotificationUID == uid);

                            if (notification != null)
                            {
                                notification.NotificationFollowed = true;
                                notification.NotificationCleared = true;
                                notification.NotificationSeen = true;
                            }

                            mh.Context.SaveChanges();
                        }

                        router.PerformRoute(_lastNotifiactions[number - 1].NotificationPath);
                    }
                }
                else if (selection.ToLower() == "e" || selection.ToLower() == "email")
                {
                    router.PerformRoute("WorldBankBBS.EMail:WorldBankBBS.EMail.EMailPathHandler:EnterEmailSection");
                }
                else if (selection.ToLower() == "s" || selection.ToLower().StartsWith("sub"))
                {
                    router.PerformRoute("WorldBankBBS.Subboards:WorldBankBBS.Subboards.SubboardPathHandler:EnterMessageSection");
                }
                else if (selection.ToLower() == "w" || selection.ToLower().StartsWith("width"))
                {
                    SetWidth();
                }
                else if (selection.ToLower() == "n" || selection.ToLower().StartsWith("news"))
                {
                    router.PerformRoute("WorldBankBBS.Handlers:WorldBankBBS.Handlers.PostLoginHandler:DisplayNews");
                }
                else if (selection == "?")
                {
                    DisplayMenu(translator);
                }
                else if (selection.ToLower() == "q" || selection.ToLower() == "quit")
                {
                    DisplayGoodbye(translator);
                    break;
                }

                Thread.Sleep(100);
            }
        }

        private void SetWidth()
        {
            var buffer = new byte[1024];
            var l = _translator.StringToBytes(buffer, StringTable.MAIN_SET_WIDTH);
            _session.Connection.SendData(buffer, 0, l);

            TextInput -= _inputHandler.OnTextInput;
            TextInput += _inputHandler.OnTextInput;

            var translator = _session.Encoding.GetTranslator(_session);

            var selection = TextInput(_session, translator, _session.Connection, 3, false);

            TextInput -= _inputHandler.OnTextInput;

            int temp;

            if (Int32.TryParse(selection, out temp))
            {
                if (temp != (int) _session["ScreenWidth"])
                {
                    _session["ScreenWidth"] = temp;

                    using (var mh = new ModelHelper())
                    {
                        mh.BeginNewContext();

                        var user = mh.Context.Users.FirstOrDefault(x => x.UserUID == _session.User.UserUID);

                        if (user != null) // Yeah, like it could be null
                        {
                            if (user.UserPreference == null)
                            {
                                var up = new UserPreference
                                {
                                    UserUID = _session.User.UserUID,
                                    HelpLevel = (int) _session["HelpLevel"],
                                    ScreenHeight = temp,
                                    ScreenWidth = (int) _session["ScreenWidth"],
                                };

                                mh.Context.UserPreferences.Add(up);
                            }
                            else
                            {
                                user.UserPreference.ScreenWidth = temp;
                            }

                            mh.Context.SaveChanges();
                        }
                    }
                }
            }
        }

        private void DisplayGoodbye(ITranslator translator)
        {
            var buffer = new byte[1024];
            var l = 0;
            l = translator.StringToBytes(buffer, StringTable.MAIN_GOODBYE);
            _session.Connection.SendData(buffer, 0, l, l);
        }

        private void DisplayMenu(ITranslator translator)
        {
            var buffer = new byte[1024];
            var l = 0;
            l = translator.StringToBytes(buffer, StringTable.MAIN_GENERIC_MENU);
            _session.Connection.SendData(buffer, 0, l, l);
        }

        private void DisplayPrompt(ITranslator translator)
        {
            var buffer = new byte[1024];
            var l = 0;
            using (var mh = new ModelHelper())
            {
                mh.BeginNewContext();
                _lastNotifiactions =
                    mh.Context.Notifications.Where(x => x.UserUID == _session.User.UserUID && !x.NotificationSeen)
                        .OrderBy(x => x.Timestamp).Take(5).ToList();

                l = translator.StringToBytes(buffer, StringTable.MAIN_PROMPT_TOP);
                _session.Connection.SendData(buffer, 0, l, l);

                for (int i = 0; i < _lastNotifiactions.Count; ++i)
                {
                    var text = _lastNotifiactions[i].NotificationText;
                    if (text.Length > 37 && _session.Encoding == "PETSCII") text = text.Substring(0, 37);
                    if (text.Length > 77) text = text.Substring(0, 77);

                    l = translator.StringToBytes(buffer, StringTable.MAIN_PROMPT_NOTIFICATION, i + 1, text);
                    _session.Connection.SendData(buffer, 0, l, l);
                }

                l = translator.StringToBytes(buffer, StringTable.MAIN_PROMPT_MID_1);
                _session.Connection.SendData(buffer, 0, l, l);

                l = translator.StringToBytes(buffer, StringTable.MAIN_PROMPT_1);
                _session.Connection.SendData(buffer, 0, l, l);

                l = translator.StringToBytes(buffer, StringTable.MAIN_PROMPT_2);
                _session.Connection.SendData(buffer, 0, l, l);

                l = translator.StringToBytes(buffer, StringTable.MAIN_PROMPT_BOT);
                _session.Connection.SendData(buffer, 0, l, l);
            }
        }

        public event EventHandler<Session> Login;
        public event EventHandler<Session> PreLogin;
        public event EventHandler<Session> PostLogin;
        public event EventHandler<Session> LoginFailed;

        public event EventHandler<Session> GuestLogin;
        public event EventHandler<Session> PreGuestLogin;
        public event EventHandler<Session> PostGuestLogin;



        private void DisplayBanner()
        {
            // Send connect banner.
            var buffer = new byte[1024];

            if (!(_translator is CbmTranslator))
            {
                buffer[0] = 0xff;
                buffer[1] = 0xfd;
                buffer[2] = 0x2d;

                buffer[3] = 0xff;
                buffer[4] = 0xfd;
                buffer[5] = 0x03;

                buffer[6] = 0xff;
                buffer[7] = 0xfe;
                buffer[8] = 0x22;

                buffer[9] = 27;
                buffer[10] = (byte)')';
                buffer[11] = (byte)'0';

                _session.Connection.SendData(buffer, 0, 12);
            }

            var l = _translator.StringToBytes(buffer, StringTable.BBS_CONNECT);
            _session.Connection.SendData(buffer, 0, l);

            l = _translator.StringToBytes(buffer, StringTable.BANNER_CONNECT);
            _session.Connection.SendData(buffer, 0, l);

            buffer[0] = 0;

            while (buffer[0] != '\n' && buffer[0] != 13)
            {
                while (!_session.Connection.HasData) Thread.Sleep(100);
                _session.Connection.ReadData(buffer, 0, 1);
            }
        }
    }
}
